Repository navigation
Folia Support

How DZEconomy runs on Folia, Paper's region-based multithreading fork.
Folia divides the world into independent regions that tick in parallel on multiple threads, instead of one main thread.
| Aspect | Paper | Folia |
|---|---|---|
| Threading | One main thread | Multiple region threads |
| Scheduling | Bukkit.getScheduler() |
Global, region, and entity schedulers |
| Thread safety | Not required | Required |
| Compatibility | Any plugin | Only Folia-aware plugins |
DZEconomy routes all scheduling through FoliaAdapter, a utility class that detects Folia at startup and picks the right scheduler.
On class load, DZEconomy checks for io.papermc.paper.threadedregions.RegionizedServer. When found, it initializes the Folia scheduler methods through reflection.
| Scheduler | Use Case | DZEconomy Usage |
|---|---|---|
| GlobalRegionScheduler | Tasks not tied to a location or entity | Auto-save, daily reset, update checks, combat tag cleanup |
| RegionScheduler | Tasks for a specific location | Location-bound work |
| EntityScheduler | Tasks for a specific entity | Player notifications, reward delivery |
| AsyncScheduler | Off-thread work | Database operations |
FoliaAdapter.isFolia() // true when running Folia
FoliaAdapter.runTask(plugin, () -> { ... }) // next tick, global/main thread
FoliaAdapter.runTaskAsynchronously(plugin, () -> { ... })
FoliaAdapter.runTaskLater(plugin, () -> { ... }, delayTicks)
FoliaAdapter.runTaskTimer(plugin, () -> { ... }, delayTicks, periodTicks)
FoliaAdapter.runTaskTimerAsynchronously(plugin, () -> { ... }, delayTicks, periodTicks)
FoliaAdapter.runAtEntity(plugin, entity, () -> { ... })
FoliaAdapter.runAtLocation(plugin, location, () -> { ... })
FoliaAdapter.cancelTasks(plugin)Every call returns a FoliaTask handle with a single cancel() method, no matter which scheduler backed it.
All balance-modifying operations are safe from any thread:
- Per-player locks — each player has their own lock
- Atomic transfers — a two-phase commit keeps transfers consistent
-
Concurrent collections — data caches use
ConcurrentHashMap - Async storage — database writes run off the tick loop
| Feature | Status |
|---|---|
| Multi-currency balances | Full support |
| Player-to-player transfers | Full support |
| Payment requests | Full support |
| Baltop | Full support |
| Mob rewards | Full support |
| PVP loot | Full support |
| Combat tag | Full support |
| Auto-save | Full support |
| MySQL storage | Full support |
| SQLite storage | Full support |
| PlaceholderAPI | Full support |
| LuckPerms integration | Full support |
| Rank multipliers | Full support |
| Currency conversion | Full support |
| Payall | Full support |
| Update checker | Full support |
| Config reload | Full support |
Folia schedulers require a minimum delay of 1 tick for delayed and repeating tasks. FoliaAdapter clamps all delays to at least 1.
When an entity retires, its scheduled tasks are cancelled. DZEconomy handles this without errors: combat tag tasks clean up on quit, player data saves asynchronously on disconnect, and the retirement callback is a no-op.
Folia has no single main thread. Code that shipped expecting a main thread must run on the owning region's thread. The adapter routes runAtEntity, runAtLocation, and runTask accordingly.
Because the Folia scheduler classes only exist on Folia, the adapter loads them through reflection at startup. Standard Bukkit servers never touch that code path, so they get no class-loading errors.
Folia helps servers where many players spread across different areas:
| Metric | Paper (100 players) | Folia (100 players) |
|---|---|---|
| TPS | Can dip below 20 | Stable at 20 |
| Economy operations | Fast, one thread | Fast, parallel regions |
| Auto-save impact | Possible lag spike | Distributed |
| Mob reward processing | Sequential | Parallel by region |
Balance lookups hit the in-memory cache in constant time on both platforms. Balance changes only contend on the same player's lock, so different players never block each other.
- Use MySQL for multi-server networks. SQLite is fine for a single Folia server.
- Keep the auto-save interval reasonable. Folia spreads the load, but fewer saves still helps.
- Disable features you do not use. PVP loot and combat tag off means fewer scheduled tasks.
"Not on the main thread" errors
No such thing exists on Folia. If you see this from another plugin, that plugin calls Bukkit.getScheduler() directly and will not work on Folia. DZEconomy never does.
Tasks not executing
Check whether the entity or location is still valid. A retired entity never runs its scheduled tasks. Confirm console shows DZEconomy enabled normally.
Performance regression
- Confirm your Folia build is current (1.19.4+).
- Check whether another plugin is the bottleneck, not DZEconomy.
- Raise
auto-save.intervalif the save tasks contend with gameplay regions.
See Version Coverage for supported Folia versions.
DZEconomy GitHub • Discord Support • Wiki Home
Developed by DemonZ Development