Folia support was contributed by RiceChen_ (RICE0707) in #1 — including the source-set isolation that keeps
folia-apioff the main compile classpath. Thank you!
Added
- Folia support.
folia-supported: trueis declared, and every scheduled task now runs on the thread that owns the data it touches: block work on the owning region,/kyo giveeligibleon the recipient's entity scheduler, and the dirty-position flush (which only writes SQLite) on the global region. Spigot and Paper behaviour is unchanged — the same code path resolves toBukkit.getScheduler()there. The startup line reports which mode is active (scheduler: Folia regionized/Bukkit main thread). - Admin commands that read or write blocks (
inspect,preview,sample,markeligible,resolve) now run on the thread that owns the target coordinate — inline when the current thread already owns it, scheduled onto the owning region otherwise. On Folia a console command runs on the global thread, which owns no blocks at all, so these would otherwise have thrown. Spigot and Paper always dispatch commands on the main thread, so the inline path is always taken there and replies — including over RCON — behave exactly as in 1.1.0. Known limit: on Folia, an RCON command that has to hop regions gets an empty RCON response (the response buffer is flushed when dispatch returns and cannot wait for another thread).
Changed
- Folia's scheduler API is compiled in a separate
foliasource set, not added tomain.folia-apitransitively exposes the whole Paper API, so putting it onmain's compile classpath would have silently retired the [1.0.0] guarantee that Spigot compatibility is a compile-time fact.mainstill sees onlyspigot-api; the one file that calls Folia (FoliaSchedulers) is loaded only when running on Folia, andSchedulersSpigotSafetyTestfails if a Folia reference ever reaches the class Spigot does load. database.dirty_flush_interval_ticksbelow1is now clamped to1. Bukkit silently did this already; Folia rejects it outright, so the same config would have failed startup there.api-versionlowered from26.2to26.1. Folia's newest release is 26.1.2 — no 26.2 build exists — and a server refuses to load a plugin whoseapi-versionis above its own version, so this is the price of one jar running on all three platforms. The compile baseline is unchanged (spigot-api26.2); on Spigot/Paper 26.2 the plugin now merely declares the older API level.
Fixed
- Dirty positions could be lost on Folia, which is an exploit problem rather than mere data loss — a dropped dirty flag makes a block a player covered up "first-exposure resolvable" again, reopening the cover-and-dig hole. Each chunk's position set was a plain
HashSet, safe on Spigot only becausemarkDirtyand the flush task shared the main thread. Under regionized scheduling the flush runs on the global thread and encodes the set while a region thread is still adding to it, throwingConcurrentModificationExceptionmid-write. The per-chunk sets are now concurrent;DirtyPositionConcurrencyTestreproduces the original failure. Spigot and Paper were never affected. - A failed dirty-position flush no longer drops the chunk from the flush queue: the chunk is requeued for the next cycle and the failure is logged, and one chunk's failure no longer aborts the rest of the cycle. Relevant on Folia, where region threads and the global flush task can hit SQLite concurrently and collide with
SQLITE_BUSY; previously the pending flag was consumed before the write, so a failed write meant those dirty positions were never retried — the same exploit-reopening loss the flush-interval note in CONFIG.md warns about.