Releases: TinyYana/Kyokalith
Release list
Kyokalith v1.2.0
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.
Kyokalith v1.1.0
Changed
- Eligibility now includes already-exposed vanilla ore. Previously, only ore Kyokalith itself materialized on first exposure (
NATURAL_BLOCK) or moved through the placed-block token flow (PLACED_BLOCK) could fireOreCheckTriggerEvent. Ore that was already exposed at world generation — cave walls, ravine faces, i.e. most of what a player actually mines while exploring — almost never coincidentally matched the deterministic vein function, so it silently never fired the event. That exclusion caught zero cheaters (X-Ray gives no informational edge on ore that's already visible) while starving downstream reward plugins of legitimate check opportunities: a server measured zero triggers across ~200 ores mined in ordinary cave exploration. A newEligibilitySource.WORLDGEN_EXPOSEDnow covers this case — any real, currently-standing ore of an enabled type that isn't in a dirty position is eligible. Anti-X-Ray guarantees are unaffected: this only changes reward-check eligibility, not the decoy/materialization logic that decides what's real. See docs/API.md.
Kyokalith v1.0.0
First public release. The decoy-materialization model shipping here has been running in production on a live survival server for the past two weeks without incident.
What Kyokalith is, in one paragraph: anti-X-Ray that never touches world generation. Vanilla ores generate exactly as always; any ore fully enclosed by solid blocks is a decoy — X-Ray, freecam, and seed-map tools all see it, but whether the block is real is only decided the moment mining first exposes it, by a deterministic function keyed with a private per-server salt. Cheaters tunnel to what they saw through the wall and hit stone; ore an honest player can see is always real. Per-event cost is a constant (removed blocks × 6 neighbor checks) — no packet obfuscation, no chunk scanning. See the README for the full model.
Added
- Customizable messages / locales. All admin-command output moved out of the code into
plugins/Kyokalith/lang/<locale>.yml. Bundled locales:en(default) andzh_TW; new config keylocaleselects one. Edit the generated files to customize — deleted keys fall back to the built-in text, and any key missing from a locale falls back to English. Add your ownlang/<name>.ymland setlocale: <name>for a new language, no code required. - Tab completion for every
/kyosubcommand: subcommand names, coordinates (pre-filled from the block you're looking at, or your position), world names, online player names, ore type ids, radius/amount suggestions. Players withoutkyokalith.adminget no completions. - LICENSE: TinyYana Universal Software License (TYUSL) 1.0 — free to use, modify, integrate, and redistribute (commercial servers included); selling the plugin itself or repackaging it as a paid product requires written permission.
- English documentation as the primary set: README.md, docs/CONFIG.md, docs/API.md. 繁體中文版本: README.zh-TW.md, docs/CONFIG.zh-TW.md, docs/API.zh-TW.md.
- Automated releases: pushing a
v*tag builds, tests, verifies the tag matchesgradle.properties, and publishes a GitHub Release with the jar and this file's matching section as notes.
Changed
- Compiled against the Spigot API (26.2) instead of the Paper API. The single Paper-only call in the codebase (
pluginMeta) was replaced with the Bukkit equivalent, making Spigot compatibility a compile-time fact. Production testing still runs on Paper; Folia is not supported. - Kotlin runtime pinned to stable 2.4.0 (was
2.4.20-Beta1); thelibraries:entry in plugin.yml that the Bukkit library loader downloads at startup matches. - Console/log messages are now English.
/kyo statsoutput no longer leaks internal reward-system terminology ("d20"). - Plugin metadata (description, docs) no longer references the private server project this plugin originated from; source comments that pointed at a private design document now explain the concepts inline or link to
docs/in this repo.
Fixed
processResourcesnow registers the version as a task input — previously an incremental build after bumping onlygradle.propertiescould produce a jar whose embeddedplugin.ymlstill carried the old version string.
Upgrading from a pre-release 0.x build
Drop-in: replace the jar and restart.
- Your existing
config.ymlis kept as-is; the newlocale: enkey is merged in automatically with your values and comments untouched. Setlocale: zh_TWfor Traditional Chinese admin output. plugins/Kyokalith/lang/is created with editable copies of both bundled locales.- Database schema, the
salt, and all tracked state are unchanged — no migration, nothing re-rolls.