Fixed:
- MapSeedInterceptor filtered map icons against "TREASURE"/"PILLAGER"/"BASTION",
none of which are real vanilla map decoration IDs (verified against
org.bukkit.map.MapCursor.Type directly - no such constants exist). Buried
treasure maps actually use TARGET_X, which was missing entirely, so treasure
locations were never actually scrambled despite being a named threat-model
signal. Now matches TARGET_X; the two dead checks were removed.
- EndCityProtector and EndSpikeProtector both marked a chunk/world "already
processed" as soon as it was scanned, even when modify_world was off and
nothing was changed. Turning modify_world on later (including via
/asc toggle) would silently do nothing for anything already loaded once
while it was off. Both now only mark "done" when the modification actually
ran, or (End Cities) when a chunk provably has no End City at all.
- All four dragon-respawn end crystals independently started their own
300-attempt polling loop to detect the end of the respawn animation - 4x
the necessary scheduled work per fight. Now guarded to one loop per world.
Optimized:
- Replaced reflection-based scheduled-task cancellation in FoliaSchedulerUtil
with direct typed ScheduledTask#cancel() calls (verified against the real
Paper API); a genuine cancel failure is no longer silently swallowed.
- Removed a pointless seconds->ticks->seconds round-trip in the seed rotation
interval config.
- Simplified the End Spike pillar-angle formula to a plain decagon spacing
expression (behaviorally identical, verified via cos/sin periodicity).
- Trimmed default config.yml to essential settings; fuller explanations live
in the README instead of long inline comments.
modrinth.txt rewritten for a stronger hook and clearer structure (protection
layers grouped into network/world/detection categories), with real Build/
Release/License/Java badges and version references bumped to 3.5.0.1.
Also fixes a repo-wide bug: every self-referential GitHub URL (README badges,
modrinth.txt, issue template) pointed to github.com/SunsetRQ/AntiSeedCracker,
missing the "7" - the actual repo is SunsetRQ7/AntiSeedCracker. Every badge
image and "view on GitHub" link was silently broken.
Eye of Ender redirection only overrode initial velocity, but vanilla EnderSignal
re-accelerates toward its stored target location every tick regardless, so eyes
curved back toward the real stronghold within a second or two of flight. Now also
sets the target location toward the fake stronghold.
initPlayer() also unconditionally re-rolled each online player's fake stronghold on
every /asc reload and /asc toggle, silently breaking the answer-consistency /locate
and Eye of Ender redirection depend on. Now only assigned once per player.
Adds modrinthchangelog.txt for publishing release notes to Modrinth.
Live testing on a real Paper 26.1.2 server surfaced a real bypass (/execute run seed
skipped the command blocker entirely since vanilla's internal re-dispatch never
re-fires PlayerCommandPreprocessEvent) plus two bugs only visible under real RCON
usage: /asc stats output bleeding into the next command's response, and Windows
console mojibake from non-ASCII characters in logger output. Also fixes a build-
breaking Java 21/25 mismatch, unbounded cache growth in the structure recon
monitor, and /locate answers re-randomizing on repeated queries instead of
staying consistent.
Adds: /asc toggle <feature> [true|false] for live per-feature config changes,
granular admin permissions (status vs manage), a non-punishing command-probing
monitor, and a configurable structure-recon tracked-structures list. README
threat model expanded with competitor research (SeedCrackerX, LiquidBounce,
Wurst, Meteor Client, and other anti-seed-cracker plugins) and honest known
limitations.
- pluginConfig/databaseManager were plain fields reassigned by /asc reload
on the main thread but read from PacketEvents Netty threads and async
scheduler threads with no happens-before edge; mark volatile
- extra_blocked_commands list was never lowercased at load, so any
mixed-case entry in config.yml silently failed to match and block —
a real gap in a security-relevant feature
- StructureReconMonitor called chunk.getStructures() on every chunk
crossing for every player with no cross-player caching; add a
per-world chunk-level cache so each chunk's structure lookup happens
once total, not once per player per visit. Also add ANCIENT_CITY to
the tracked structure set
- DatabaseManager opened and closed a new file handle for every single
audit event; keep a persistent writer open, rotated only on date
change, flushed per write, closed cleanly on shutdown
- Remove dead code left over from the removed WorldSeedInterceptor:
SeedManager.worldSeeds/assignWorldFakeSeed/getWorldFakeSeed/
forgetWorld and purgeOfflinePlayers had zero callers
Verified: clean compile, live-tested on Paper 26.1.2-74 and Folia
26.1.2-8 with zero errors, real seed confirmed byte-for-byte intact
in world_gen_settings.dat after each run.
Root cause of Modrinth stability complaints: WorldSeedInterceptor patched
the live NMS seed field every second on every world. That field is
re-read fresh by vanilla chunk decoration (trees, ores, structure
placement) for every chunk generated, not cached once at world load, so
any chunk decorated while the field held a fake value generated from
random garbage instead of the real seed. This explains the reported
"seed changing every few seconds disrupts chunk generation" and "issues
with other plugins/server core" reports.
- Remove WorldSeedInterceptor and the "Plugin API Protection" feature
entirely; replace with SeedIntegrityMonitor, a read-only watchdog that
only ever reads world.getSeed() and warns on drift, never writes to it
- Verified fix by booting real Paper 26.1.2 and Folia 26.1.2 servers with
explicit known seeds and confirming byte-for-byte on-disk seed integrity
in world_gen_settings.dat after extended runtime
- EndCityProtector now scans only the structure's bounding box instead of
the full chunk column (up to 256x256 blocks reduced to structure size)
- Player-seed safety-net task reduced from 1s to 15s interval (no longer
has seed-patching work driving the need for high frequency)
- Researched LiquidBounce/SeedCrackerX mechanics: seed cracking is
primarily done via real coordinates of legitimately-visited structures,
which is not a network exploit and cannot be prevented server-side.
Documented this honestly instead of overclaiming
- Add StructureReconMonitor: detects (audit-log only, never blocks) the
specific multi-structure visitation pattern SeedCrackerX data-gathering
produces
- Add SlimeChunkObfuscator (opt-in, off by default): cancels natural
slime spawns to deny slime-chunk-sampling-based cracking
- Document that block/ore ESP (XRay, StorageESP) is a different threat
class solved by Paper's native anti-xray, not by this plugin
- Fix modrinth.txt, which previously claimed "world generation is never
altered" while the plugin's own API-protection layer was doing exactly
that
- Add bStats (plugin id 32378), relocated to me.legendcraft.antiseedcracker.lib.bstats, with platform/protection charts
- Upgrade PacketEvents 2.12.2 -> 2.13.0
- Configurable seed-blocked messages via config.yml messages section
- reload() now applies database enable/disable without restart
- Strip debug symbols from shipped bytecode
- Add contents:write permission to release workflow
- Verified live: Paper 26.1.2-72 and Folia 26.1.2-8 boot with zero errors, WorldSeedInterceptor active on both
PacketEvents declares adventure-nbt as a compile dependency but does not
bundle it inside its own jar. The server does not expose net.kyori.adventure.nbt
to plugin classloaders, causing NoClassDefFoundError: net/kyori/adventure/nbt/BinaryTag
at startup inside SynchronizedRegistriesHandler.
Fixes:
- Remove adventure-nbt exclusion filter from maven-shade-plugin so all 75
net.kyori.adventure.nbt classes are bundled in the shaded jar
- Upgrade PacketEvents 2.12.0 -> 2.12.2 (adventure-nbt 4.25.0 -> 4.26.1,
improved compatibility with modern Paper/Folia builds)
- Bump plugin version 3.1.0 -> 3.1.1