worker-threads: -1 means "auto", and auto on 4 cores resolves to ONE worker.
MoonriseCommon.adjustWorkerThreads halves availableProcessors and then, if the
result is <= 4, collapses it further - 4/2=2, and 2<=3 becomes 1. That single
thread generated the spawn region serially.
Measured on zern.cc (4 vCPU, 8 GB), same jar, same flags, cold world vs warm:
before after
cold, overworld 6770ms 2944ms
cold, nether 1368ms 888ms
cold, total 38.5s 24.9s
warm, overworld 1084ms 803ms
warm, total 16.4s 12.2s
gen-parallelism "default" already resolved to true at startup, so it is now
spelled out rather than left to string comparison at boot.
3 workers is deliberately NOT set here. The main thread plus Netty share the
same 4 cores, and going to 3 trades main-thread headroom for generation that
does not happen every tick. That needs a profile, not a guess.
Also recorded the corollary: player-max-concurrent-chunk-generates is a rate
limiter, not an accelerator. Speeding up generation without raising it just
makes the engine faster behind a throttle that was sized for the old speed.
The README still described decoupled sound range as planned and had no
`/delta displaylead`, no mention of the config being writable, and a command
list containing a `/delta reload` that does not exist.
Also corrects two claims that no longer hold:
- the Display tracking clamp is in org.spigotmc.TrackingRange, not
ChunkMap.TrackedEntity. That was a deliberate choice: TrackingRange is
git-tracked Paper source, so the decompiled Minecraft tree stays untouched.
- the new Bukkit methods are default methods, so plugins referencing them keep
working on stock Paper instead of failing with NoSuchMethodError.
0373806e2 and 0817a5706 were pushed but never built, so the server jar was
broken on main. Six compile errors, all in code that had never run:
- ClientboundSoundPacket takes Holder<SoundEvent> in 1.21, not SoundEvent.
- CraftWorld has no getServer(); the vanilla handle does.
- Server has no paperConfigurations()/registryAccess() - Configurations is
reachable through the console, and saveGlobalSection lives on Configurations
(GlobalConfiguration is a ConfigurationPart, i.e. the data, not the writer).
- ServerPlayer.server is private.
DeltaSound pumped delayed packets through BukkitScheduler, which requires a
live Plugin, and Delta as a core has none. It now uses GlobalRegionScheduler
with a null plugin, which exists precisely for core tasks. Delays are counted
in game ticks via Bukkit#getCurrentTick rather than System.nanoTime, so they
no longer stretch under lag. The pump cancels itself once the queue drains.
New DeltaDisplay holds the predictive-teleport policy (lead range, default,
application) and /delta displaylead tunes it. Honest about its scope:
Display#setTeleportDuration is already stock Bukkit, so Delta adds no new API
to plugins and breaks no compatibility - it centralises the policy and reports
it. The position shift itself is done by the plugin, per visual, along that
visual's own trajectory.
DeltaBuild now registers the existing features in the startup banner instead of
printing "no custom features registered". The banner is emitted from a static
initialiser before paper-global.yml is parsed, so the strings describe the
mechanism and point at /delta status for live values rather than printing
defaults as if they were the running configuration.
When converting to components:
- Remove enchantments with levels <= 0
- Remove the item name if it is not valid JSON
- Remove lore entries that are not valid JSON
The chunk system may not be responsive in a shutdown (i.e
watchdog timeout). Therefore, we should avoid interacting
with the chunk system to increase the odds of a graceful
shutdown.